/*
 *  PMVect.h
 *  PezMonkey
 *
 *  Created by Spence DiNicolantonio on 10/28/09.
 *  Copyright 2009 Necrosoft. All rights reserved.
 *
 */


/**
 * A 2-dimensional vector. This structure is interchangeable with Chipmunk's 
 * cpVect structure.
 */

#import <Foundation/Foundation.h>
#import "chipmunk.h"


#pragma mark Type Definition
typedef cpVect PMVect;
static const PMVect PMVectZero = {0.0, 0.0};


#pragma mark -
#pragma mark Static Inline Functions

/**
 * Constructs a PMVect structure with given x and y component values.
 */
static inline PMVect PMVectMake(const PMFloat x, const PMFloat y) {
	return (PMVect) cpv(x, y);
}

/**
 * Constructs a PMVect structure out of a given CGPoint.
 */
static inline PMVect PMVectWithPoint(CGPoint p) {
	return PMVectMake(p.x, p.y);
}

/**
 * Calculates the sum of two given vectors.
 */
static inline PMVect PMVectAdd(const PMVect v1, const PMVect v2) {
	return (PMVect) cpvadd(v1, v2);
}
							
/**
 * Calculates the inverse of a given vector.
 */
static inline PMVect PMVectInverse(const PMVect v) {
	return (PMVect) cpvneg(v);
}

/**
 * Calculates the difference between two given vectors (v1 - v2).
 */		   
static inline PMVect PMVectSub(const PMVect v1, const PMVect v2) {
	return (PMVect) cpvsub(v1, v2);
}
			
/**
 * Calculates the product of a given vector and scalar value.
 */
static inline PMVect PMVectMult(const PMVect v, const PMFloat s) {
	return (PMVect) cpvmult(v, s);
}
		
/**
 * Calculates the scalar dot product of two given vectors.
 */
static inline PMFloat PMVectDot(const PMVect v1, const PMVect v2) {
	return cpvdot(v1, v2);
}
	
/**
 * Calculates the vector cross product of two given vectors.
 */
static inline PMFloat PMVectCross(const PMVect v1, const PMVect v2) {
	return cpvcross(v1, v2);
}
	
/**
 * Calculates the vector perpendicular to a given vector (90 degree rotation).
 */
static inline PMVect PMVectPerp(const PMVect v) {
	return (PMVect) cpvperp(v);
}
	
/**
 * Calculates the vector perpendicular to a given vector (-90 degree rotation).
 */
static inline PMVect PMVectPerpInverse(const PMVect v) {
	return (PMVect) cpvrperp(v);
}
				
/**
 * Calculates the vector projection of two given vectors.
 */
static inline PMVect PMVectProject(const PMVect v1, const PMVect v2) {
	return (PMVect) cpvproject(v1, v2);
}
				
/**
 * Rotates a given vector by a given rotation vector.
 */
static inline PMVect PMVectRotate(const PMVect v1, const PMVect rot) {
	return (PMVect) cpvrotate(v1, rot);
}
		
/**
 * Rotates a given vector by the oposite of a given rotation vector.
 */
static inline PMVect PMVectRotateInv(const PMVect v1, const PMVect v2) {
	return (PMVect) cpvunrotate(v1, v2);
}

/**
 * Calculates the distance between two given vectors.
 */
static inline PMFloat PMVectDist(const PMVect v1, const PMVect v2) {
	return cpvdist(v1, v2);
}

/**
 * Calculates the squared distance between two given vectors. This is faster 
 * than PMVectDist() when only comparing distances.
 */
static inline PMFloat PMVectDistSQ(const PMVect v1, const PMVect v2) {
	return cpvdistsq(v1, v2);
}

/**
 * Calculates the the linear interpolation between two given vectors by a given
 * percentage. The given distance percentage should be given as a float in the 
 * range [0.0, 1.0].
 */
static inline PMVect PMVectLerp(const PMVect v1, const PMVect v2, const PMFloat i) {
	return cpvlerp(v1, v2, i);
}

/**
 * Calculates the the linear interpolation between two given vectors across a given 
 * distance.
 */
static inline PMVect PMVectLerpConst(const PMVect v1, const PMVect v2, const PMFloat d) {
	return cpvlerpconst(v1, v2, d);
}

/**
 * Calculates the spherical interpolation between two given vectors by a given 
 * percentage. The given distance percentage should be given as a float in the 
 * range [0.0, 1.0].
 */
static inline PMVect PMVectSLerp(const PMVect v1, const PMVect v2, const PMFloat i) {
	return cpvslerp(v1, v2, i);
}

/**
 * Calculates the spherical interpolation between two given vectors accross a
 * given angle, in radians.
 */
static inline PMVect PMVectSLerpConst(const PMVect v1, const PMVect v2, const PMFloat a) {
	return cpvslerpconst(v1, v2, a);
}

/**
 * Determines whether two given vectors are equivalent.
 */
static inline BOOL PMVectEquals(const PMVect v1, const PMVect v2) {
	return (v1.x == v2.x && v1.y == v2.y);
}
	

#pragma mark -
#pragma mark Other Functions

/**
 * Calculates the magnitude of a given vector.
 */
static PMFloat PMVectMag(const PMVect v) {
	return cpvlength(v);
}

/**
 * Same as PMVectMag().
 */
static PMFloat PMVectLength(const PMVect v) {
	return PMVectMag(v);
}

/**
 * Calculates the squared magnitude of a given vector. This is faster than 
 * PMVectMag() when only comparing magnitudes.
 */
static PMFloat PMVectMagSQ(const PMVect v) {
	return cpvlengthsq(v);
}

/**
 * Same as PMVectMagSQ().
 */
static PMFloat PMVectLengthSQ(const PMVect v) {
	return PMVectMagSQ(v);
}

/**
 * Calculates the result of normalizing a given vector.
 */
static PMVect PMVectNormalize(const PMVect v) {
	return (PMVect) cpvnormalize(v);
}

/**
 * Creates a unit vector with same direction as a given vector. Same as PMVectNormalize().
 */
static PMVect PMVectUnitVect(const PMVect v) {
	return PMVectNormalize(v);
}

/**
 * Calculates the rotation vector for a given angle, in radians.
 */
static PMVect PMVectForAngle(const PMFloat a) {
	return (PMVect) cpvforangle(a);
}

/**
 * Calculates the angle for a given rotation vector.
 */
static PMFloat PMVectToAngle(const PMVect v) {
	return cpvtoangle(v);
}

/**
 * Returns a NSString object describing a given vector.
 */
static NSString* PMVectToString(const PMVect v) {
	return [NSString stringWithFormat:@"(%0.3f, %0.3f)", v.x, v.y];
}

/**
 * Creates a PMVector structure with a given magnitude and direction.
 */
static PMVect PMVectWithMagDir(const PMFloat mag, const PMVect dir) {
	PMVect unitVect = PMVectUnitVect(dir);
	PMFloat x = unitVect.x * mag;
	PMFloat y = unitVect.y * mag;
	
	return PMVectMake(x, y);
}
